import platform
import time
from typing import List
from typing import Dict
from files import *
from Convertor import Convertor


class DictItem:
    """
    字典中的一个条目
    """

    def __init__(self, text: str, code: str, weight=0) -> None:
        super().__init__()
        self.text = text
        self.code = code
        self.weight = weight

    def __str__(self) -> str:
        return f'{self.text}\t{self.code}\t{self.weight}'


def _parse_line(line: str) -> DictItem or None:
    if not line or line.startswith('#') or len(line.strip()) == 0:
        return None

    arr = line.strip().split('\t', maxsplit=3)
    text = arr[0]
    code = arr[1] if len(arr) > 1 else ''
    weight = int(arr[2]) if len(arr) > 2 else 0
    return DictItem(text, code, weight)


def _load_items(txt_file) -> List[DictItem]:
    items = []
    file_must_exist(txt_file)
    with open_utf8_read(txt_file) as f:
        for line in f:
            item = _parse_line(line)
            if item:
                items.append(item)
    return items


class DictTxt:
    """
    文本格式的字典，格式：词条\t编码\t权重(可选)，示例：
    啊	0x554a
    嬢	niang	1
    阿爸	a ba	6170
    """

    def __init__(self) -> None:
        super().__init__()
        self.source = None
        self.convertor: Convertor = None
        self.aux_sources = None
        self.items: List[DictItem] = []
        self.aux_codes: Dict[str, str] = {}
        self.aux_length = 2  # 辅助码默认取两位
        self.aux_for_words_length = 1  # 默认只为单字添加辅助码
        self.convert_first = True  # 先转换编码，再添加辅助码
        if platform.system() == 'Windows':
            self.version = time.strftime("%y.%m.%#d%H", time.localtime())
        else:
            self.version = time.strftime("%y.%m.%-d%H", time.localtime())

    def set_aux_for_words_length(self, length=1):
        self.aux_for_words_length = length

    def set_convert_first(self, enable=True):
        self.convert_first = enable

    def convert(self, txt_file, convertor: Convertor or None, aux_source, aux_length):
        file_must_exist(txt_file)
        self.source = txt_file
        self.aux_sources = aux_source
        self.aux_length = aux_length or 2
        self.convertor = convertor
        self._load_aux_codes()
        self.items = _load_items(self.source)
        self._convert_items()

    def write_yaml(self, yaml_file):
        dir_ = normalize_path(yaml_file, '..')
        make_dirs(dir_)
        with open_utf8_write(yaml_file) as f:
            name = filename_of(yaml_file).split('.', maxsplit=2)[0]
            f.write(f'''#
# Rime dictionary
# Generate by imeasy: https://gitee.com/zelde/imeasy
# encoding: utf-8
#
---
name: {name}
version: '{self.version}'
sort: by_weight
use_preset_vocabulary: false     # 不使用已有词组
columns:
  - text
  - code
  - weight
...
'''
                    )
            for item in self.items:
                f.write(f'{item.text}\t{item.code}\t{item.weight}\n')

    def _load_aux_codes(self):
        if is_file_exist(self.aux_sources):
            for item in _load_items(self.aux_sources):
                if item.code:
                    self.aux_codes[item.text] = item.code

    def _convert_items(self):
        if len(self.items) == 0:
            raise ValueError('词典中没有有效的词条！')
        if self.convertor:
            if self.convert_first:
                for item in self.items:
                    print(f'convert: {item}')
                    item.code = self.convertor.convert(item.code)
                    self._add_aux_code(item)
            else:
                for item in self.items:
                    print(f'convert: {item}')
                    self._add_aux_code(item)
                    item.code = self.convertor.convert(item.code)
        else:
            for item in self.items:
                print(f'convert: {item}')
                self._add_aux_code(item)

    def _add_aux_code(self, item: DictItem):
        if self.aux_length <= 0 or len(item.text) > self.aux_for_words_length:
            return

        aux_codes = []
        if item.code.find(' ') > 0:
            for char in item.text:
                aux = self.aux_codes.get(char, '')
                aux_codes.append(aux[0:self.aux_length])
        else:
            aux = self.aux_codes.get(item.text, '')
            if aux:
                aux_codes.append(aux[0:self.aux_length])
        if len(aux_codes) == 1 and aux_codes[0]:
            item.code += (';' + aux_codes[0])
        else:
            codes = item.code.split(' ')
            new_codes = []
            for i in range(len(codes)):
                aux = aux_codes and aux_codes[i]
                if aux:
                    new_codes.append(f'{codes[i]};{aux}')
                else:
                    new_codes.append(codes[i])
            item.code = ' '.join(new_codes)
